home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DDJMAG
/
DDJ9207.ZIP
/
AVKCAPT.ZIP
/
ACCAPT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-03
|
14KB
|
488 lines
//-------------------------------------------------------------------------
// ActionMedia II Programmer's Toolkit
//
// Windows Motion Capture Sample Program
//
// Application: AvkCapt.exe
// Module Name: accapt.c
//
// description: Functions to read incoming frames from the Group Buffers
// and write them out to an AVSS file using the AVKIO file
// I/O subsystem.
//
// Copyright Intel Corp. 1991, 1992
// All Rights Reserved.
//
//-------------------------------------------------------------------------
//
// Exported functions from this module:
//
// OpenAvioFile
// CloseAvioFile
// ToggleCapture
// CaptureAvioData
//
//-------------------------------------------------------------------------
//
// Functions local to this module:
//
// ReadGrpBuf
// DispAvioErr
//
//-------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <memory.h>
#include "avkapi.h"
#include "avkio.h"
#define ACCAPT_NOEXTERNS 1
#include "avkcapt.h"
#include "disperr.h"
#include "log.h"
extern CAPT Aud;
extern CAPT Vid;
extern I16 AvkRet;
extern HAVK hGrp;
extern WORD CaptureSync;
AVIO_SUM_HDR Avio;
BOOL bAvioFileExists = FALSE;
I16 AvioRet;
static BOOL ReadGrpBuf(CAPT *, BOOL *);
I16 DispAvioErr(char *pMsg);
VIDEO_SYNC Syncs[2] = {
{ 128, 128, 240, AVK_NTSC_FULL_RATE, AVK_PA_NTSC },
{ 128, 153, 288, AVK_PAL_FULL_RATE, AVK_PA_PAL }
};
//-------------------------------------------------------------------------
//FUNCTION:
//
// BOOL OpenAvioFile(pFileSpec)
//
//PARMS IN:
//
// char *pFileSpec; name (and path) to use to create
// new AVSS file
//
//DESCRIPTION:
//
// Initialize the AVIO summary header and use it to create an AVSS file.
// This function uses the AVKIO File I/O subsystem.
//
//RETURN:
//
// TRUE on success.
// FALSE on any error (error message box is displayed before exit).
//
//-------------------------------------------------------------------------
BOOL
OpenAvioFile(char *pFileSpec)
{
AVIO_VID_SUM FAR *pVid;
AVIO_AUD_SUM FAR *pAud;
VIDEO_SYNC *pSync;
if (!*pFileSpec)
return DispErr("OpenAvioFile", "No file spec");
// Clear out the Avio structure.
_fmemset((char FAR *)&Avio, 0, sizeof(Avio));
// Initialize the structure.
Avio.SumHdrSize = sizeof(AVIO_SUM_HDR);
Avio.VidSumSize = sizeof(AVIO_VID_SUM);
Avio.AudSumSize = sizeof(AVIO_AUD_SUM);
Avio.StrmCnt = 2;
Avio.VidCnt = 1;
Avio.AudCnt = 1;
if ((AvioRet = AvioFileAlloc((AVIO_SUM_HDR FAR *)&Avio)) < 0)
return DispAvioErr("AvioFileAlloc");
// Fill out the video stream substructure.
pSync = &Syncs[CaptureSync]; // sync data (NTSC or PAL)
pVid = Avio.VidStrms;
pVid->StrmNum = 0; // video stream number
pVid->Type = AVL_T_CIM; // compressed data
pVid->SubType = AVL_ST_YVU; // packed data
pVid->StillPeriod = AVL_CIM_RANDOM_STILL; // freq of still frames
pVid->xRes = pSync->xResVid << 1; // x resolution
pVid->yRes = pSync->yResVid; // y resolution
pVid->BitmapFormat = AVK_BM_9; // bitmap format
pVid->FrameRate = pSync->FrameRate; // frame rate
pVid->PixelAspect = pSync->PixelAspect; // NTSC aspect ratio
pVid->AlgCnt = 1; // only one algorithm
pVid->AlgName[0] = AVK_RTV_2_0; // RTV 2.0 compression alg
// Fill out the audio stream substructure.
pAud = Avio.AudStrms;
pAud->StrmNum = 1; // audio stream number
pAud->LeftVol = 100; // left channel volume = 100%
pAud->RightVol = 100; // right channel volume = 100%
pAud->FrameRate = pSync->FrameRate; // frame rate
pAud->SamplesPerSecond = AUD_SAMPLE_RATE; // audio samples-per-second
pAud->AudChannel = AVK_AUD_MIX; // both speakers
pAud->AlgCnt = 1; // number of algorithms
pAud->AlgName[0] = AVK_ADPCM4; // audio ADPCM4 algorithm
// Now create the file with all standard AVSS headers.
if ((AvioRet = AvioFileCreate((char far *)pFileSpec,
(AVIO_SUM_HDR FAR *)&Avio, OF_CREATE)) < 0)
return DispAvioErr("AvioFileCreate");
bAvioFileExists = TRUE;
return TRUE;
}
//-------------------------------------------------------------------------
//FUNCTION:
//
// BOOL CloseAvioFile(VOID)
//
//DESCRIPTION:
//
// Update and lose an AVSS file using AVKIO. AvioFileUpdate() is called
// to write current information into the AVSS file's header.
//
//RETURN:
//
// TRUE on success.
// FALSE on any error (error message box is displayed before exit).
//
//-------------------------------------------------------------------------
BOOL
CloseAvioFile()
{
if (bAvioFileExists == TRUE)
{
// Update the file's header with current information that
// AVKIO keeps in the Avio summary header.
if ((AvioRet = AvioFileUpdate((AVIO_SUM_HDR FAR *)&Avio, 0)) < 0)
return DispAvioErr("AvioFileUpdate");
// Close the file.
if ((AvioRet = AvioFileClose((AVIO_SUM_HDR FAR *)&Avio)) < 0)
return DispAvioErr("AvioFileClose");
bAvioFileExists = FALSE;
}
return TRUE;
}
//-------------------------------------------------------------------------
//FUNCTION:
//
// BOOL ToggleCapture(VOID)
//
//DESCRIPTION:
//
// Toggles the capture state on or off.
//
//RETURN:
//
// TRUE on success.
// FALSE on any error (error message box is displayed before exit).
//
//-------------------------------------------------------------------------
BOOL
ToggleCapture()
{
// If no file has been opened, return.
if (!bAvioFileExists)
{
DispMsg("You must open a file before you can capture");
return TRUE;
}
switch(GetState())
{
case ST_MONITORING:
// If we are monitoring, turn on capture
// by starting the group.
if ((AvkRet = AvkGrpStart(hGrp, NOW)) != OK)
return DispAvkErr(AvkRet, "AvkGrpStart");
ToState(ST_CAPTURING);
break;
case ST_CAPTURING:
// If we are already capturing, turn it off
// by pausing the group.
if ((AvkRet = AvkGrpPause(hGrp, NOW)) != OK)
return DispAvkErr(AvkRet, "AvkGrpPause");
break;
default:
// Any other state, just do nothing - no error.
break;
}
return TRUE;
}
//-------------------------------------------------------------------------
//FUNCTION:
//
// BOOL CaptureAvioData(VOID)
//
//DESCRIPTION:
//
// This function retrieves frames from the Group Buffers in VRAM and
// writes them out to an AVSS file on disk. Each iteration of the
// main loop starts by checking whether the application's video or audio
// host RAM buffer is empty, and, if so, reading a buffer-full of frames
// from the VRAM Group Buffers. Then it loops through the video and
// audio host RAM buffers writing out matched video and audio frames
// to the AVSS file. When it runs out of either video or audio frames,
// it loops back to the top to retrieve more frames. This loop continues
// until it has retrieved all of the frames currently captured in VRAM
// or it has executed CAPTURE_LOOPS times. We use this countdown value
// to prevent the loop from executing for too long without giving the
// message loop time to run. If frames are being captured as fast as we
// are reading them, we might otherwise never exit this loop.
//
// This function is called periodically in response to either an
// AVK_CAPTURE_DATA_AVAILABLE from AVK, or a timer tick from a user-
// initiated Windows timer. It is the application programmer's
// responsibility to assure that this function is called in a timely
// manner. If AVK is capturing frames faster than the application is
// retrieving them, some frames will be lost and AVK will substitute
// dummy frames causing disruptions in playback continuity. If this
// function runs for too long at a time, the main window's message
// processing response will degrade.
//
//RETURN:
//
// TRUE on success.
// FALSE on any error (error message box is displayed before exit).
//
//-------------------------------------------------------------------------
BOOL
CaptureAvioData()
{
static BOOL bInUse = FALSE;
AVIO_FRM_HDR FAR *pFrmHdr[2]; // frame header pointers
// for video & audio
BOOL bDataRead;
int Ret;
U32 VidFrmSize, AudFrmSize;
WORD Count;
// It is rather unlikely, but possible that we will have a re-entrancy
// problem here. This routine is called either in response to an
// AVK_CAPTURE_DATA_AVAILABLE message or a timer tick. Since it
// creates a message box in the case of an error, it can allow the
// message loop to process new messages before we exit it. This
// might result in a new timer tick or AVK message causing re-entry
// before we have finished displaying the error message and killing
// the process. To prevent this contingency, we use an ownership
// semaphore. If the semaphore is set when we enter, something has
// gone wrong in the currently executing code, so, instead of just
// blocking on the semaphore, the new occurrance exits.
if (bInUse)
return TRUE;
// Now set the semaphore to indicate that the code is executing.
// The semaphore will be cleared as the last operation before a
// successful exit. Note that we do NOT clear the semaphore before
// exiting on an error condition, since we will be terminating
// the app on any error here and do not want to begin executing
// this code again between this exit and the app's termination.
bInUse = TRUE;
// Error if no buffers have been allocated.
if (!Vid.pBufHead || !Aud.pBufHead)
return DispErr("CaptureAvioData",
"NULL host RAM buffer pointer");
// Number of iterations. Without this counter, this loop might
// end up executing for long periods of time, since data may be
// coming into a Group Buffer as fast as we can retrieve it.
// This counter assures that we will exit back to the main message
// loop in a timely fashion and rely on the timer tick or the
// AVK_CAPTURE_DATA_AVAILABLE messages to recall us.
Count = CAPTURE_LOOPS;
do {
// Init the data-read flag.
bDataRead = FALSE;
// If either the video or audio host ram buffer is empty,
// retrieve more frames from VRAM. bDataRead will be set to
// TRUE if either video or audio frames were read.
if (!Vid.BufDataCnt)
{
if (!ReadGrpBuf(&Vid, &bDataRead))
return FALSE;
}
if (!Aud.BufDataCnt)
{
if (!ReadGrpBuf(&Aud, &bDataRead))
return FALSE;
}
// As long as BOTH buffers have frames, we have matched
// frames to write out. If only one buffer has data left,
// we can't write out a frame until we have retrieved
// more frames from VRAM into the other buffer.
while (Vid.BufDataCnt && Aud.BufDataCnt)
{
// Set the first frame pointer to the start of the
// next frame in the video buffer and the second
// frame pointer to the start of the next frame in
// the audio buffer.
pFrmHdr[0] = (AVIO_FRM_HDR FAR *)Vid.pBufCurr;
pFrmHdr[1] = (AVIO_FRM_HDR FAR *)Aud.pBufCurr;
if ((Ret = AvioFileFrmWrite((AVIO_SUM_HDR FAR *)&Avio,
pFrmHdr)) < 0)
return DispAvioErr("AvioFileFrmWrite");
// Increment the pointers past the current frame
// and subtract the current frame's size from the
// total bytes left in the buffers.
VidFrmSize = (U32)sizeof(AVIO_FRM_HDR)
+ pFrmHdr[0]->StrmSize[0];
Vid.pBufCurr += (WORD)VidFrmSize;
Vid.BufDataCnt -= VidFrmSize;
AudFrmSize = (U32)sizeof(AVIO_FRM_HDR)
+ pFrmHdr[1]->StrmSize[0];
Aud.pBufCurr += (WORD)AudFrmSize;
Aud.BufDataCnt -= AudFrmSize;
}
// If we have emptied a Group Buffer or executed 'Count'
// times, then we fall through and exit.
} while (bDataRead && Count--);
bInUse = FALSE;
return TRUE;
}
//-------------------------------------------------------------------------
//FUNCTION:
//
// BOOL ReadGrpBuf(pCapt, pbDataRead)
//
//PARMS IN:
//
// CAPT *pCapt; pointer to either the video or audio CAPT
// capture buffer control structure.
//
//PARMS OUT:
//
// BOOL *pbDataRead; pointer to boolean flag. This flag is set
// to TRUE if any data was retrieved. Otherwise
// its value is not changed.
//
//DESCRIPTION:
//
// Read newly captured frames from an AVK Group Buffer into one of
// the application's host RAM buffers. The count of bytes read is
// put in the CAPT structure's BufDataCnt element. If any data
// is read, the caller's flag, pbDataRead is set to TRUE.
//
//RETURN:
//
// TRUE on success.
// FALSE on any error (error message box is displayed before exit).
//
//-------------------------------------------------------------------------
static BOOL
ReadGrpBuf(CAPT *pCapt, BOOL *pbDataRead)
{
// Only refill the buffer if it is empty
if (!pCapt->BufDataCnt)
{
// Retrieve a buffer of frames.
if ((AvkRet = AvkGrpBufRead(pCapt->hGrpBuf, HOST_BUF_SIZE,
pCapt->pBufHead, &pCapt->BufDataCnt, AVK_ENABLE)) != OK)
return DispAvkErr(AvkRet, "AvkGrpBufRead");
// Set data-read flag if we read any data.
*pbDataRead = pCapt->BufDataCnt == (U32)0 ? FALSE : TRUE;
// Point back to start of buffer.
pCapt->pBufCurr = pCapt->pBufHead;
}
return TRUE;
}
//-------------------------------------------------------------------------
//FUNCTION:
//
// I16 DispAvioErr
//
//PARMS IN:
//
// char *pMsg; pointer to caller's message to be concatenated
// to the AVIO error message.
//
//DESCRIPTION:
//
// Display an Avio file I/O error message in a Windows message box. This
// message includes the error value returned from the Avio function that
// failed and a caller-supplied message that can be used to identify the
// Avio function that failed.
//
//RETURN:
//
// FALSE to indicate an error condition.
//
//-------------------------------------------------------------------------
I16
DispAvioErr(char *pMsg)
{
char Buf[128];
wsprintf((LPSTR)Buf, (LPSTR)"Avio Error 0x%04x - %s", AvioRet,
(LPSTR)pMsg);
DispMsg(Buf);
return FALSE;
}